#include "alloter.h"
#include "sys.h"
#include <string.h>

typedef uint16_t u16;
typedef uint8_t  u8;
struct _CHN_POOL_MGR chn_pool_mgr;

void init_chn_pool_mgr(void)
{
    chn_pool_mgr.free_bitmap = (1 << (sizeof(chn_pool_mgr.buffer) / BLK_SZ)) - 1; //全部空闲

}

//取最近空闲块
u8 get_last_bit_seqno(u16 x)
{
    u8 k = 0x00;
    while (0x0000 == (x & 0x0001))
    {
        k++;
        x >>= 0x01;
    }
    return (k);
}

/************************************
函数：分配缓冲区块
返回：分配的缓冲区块的标号
原理：检测free_bitmap的值，将空闲的缓冲区块标号较小的块分配，
返回分配的缓冲区块标号。
**************************************/
static u8 alloc_a_slot(void)
{
    u8 k;
    u16  bitmap;

    bitmap = chn_pool_mgr.free_bitmap;
    if (0x0000 == bitmap)//无空闲块
        return (INVALID_BLK_NO);//返回0xFF
    k = get_last_bit_seqno(bitmap);
    bitmap &= (bitmap - 1);
    chn_pool_mgr.free_bitmap = bitmap;
    chn_pool_mgr.buffer[(k << BLK_NO_SHIFT) | (BLK_SZ - 1)] = INVALID_BLK_NO;
    return (k);//返回缓冲区块中 空闲的 标号最小的标号
}

u8 put_chn_bytes(struct _CHN_SLOT * pCHN_SLOT, u8 buffer[], u8 len)
{
    u8 k, i = 0x00;

    if (len < 0x01)
        return (0);
    OS_ENTER_CRITICAL();

    while (len > 0x00)
    {
        if (pCHN_SLOT->data_cnt > MAX_BUFFER_SZ)
        {   //over limit
            goto put_chn_exit;
        }
        if (INVALID_BLK_NO == (pCHN_SLOT->rx >> BLK_NO_SHIFT))
        {
            pCHN_SLOT->tx = pCHN_SLOT->rx = alloc_a_slot() << BLK_NO_SHIFT;
            if (INVALID_BLK_NO == (pCHN_SLOT->rx >> BLK_NO_SHIFT))
            {
                goto put_chn_exit;
            }
        }
        if ((BLK_SZ - 1) == (pCHN_SLOT->rx & (BLK_SZ - 1)))
        {
            chn_pool_mgr.buffer[pCHN_SLOT->rx] = alloc_a_slot();
            if (INVALID_BLK_NO == chn_pool_mgr.buffer[pCHN_SLOT->rx])
            {
                goto put_chn_exit;
            }
            pCHN_SLOT->rx = chn_pool_mgr.buffer[pCHN_SLOT->rx] << BLK_NO_SHIFT;
        }

        k = pCHN_SLOT->rx & (BLK_SZ - 1);
        k = (BLK_SZ - 1) - k;
        if (k > len)
            k = len;
        memcpy(&chn_pool_mgr.buffer[pCHN_SLOT->rx], &buffer[i], k);
        len -= k;
        pCHN_SLOT->rx += k;
        i += k;
        pCHN_SLOT->data_cnt += k;
    }
put_chn_exit:
    OS_EXIT_CRITICAL();
    return (i);
}

u8 peek_chn_bytes(struct _CHN_SLOT * pCHN_SLOT, u8 data[], u8 len)
{
    u8 n = 0;
    struct _CHN_SLOT chn_slot;
    OS_ENTER_CRITICAL();
    chn_slot.rx = pCHN_SLOT->rx;
    chn_slot.tx = pCHN_SLOT->tx;
    chn_slot.data_cnt = pCHN_SLOT->data_cnt;
    OS_EXIT_CRITICAL();
    if (chn_slot.data_cnt > 0)
    {
        while ((len > 0) && (chn_slot.tx != chn_slot.rx))
        {
            if ((BLK_SZ - 1) == (chn_slot.tx & (BLK_SZ - 1)))
            {
                chn_slot.tx = chn_pool_mgr.buffer[chn_slot.tx] << BLK_NO_SHIFT;
            }
            data[n++] = chn_pool_mgr.buffer[chn_slot.tx];
            chn_slot.tx++;
            len--;
        }
    }

    return (n);
}

u8 get_chn_bytes(struct _CHN_SLOT * pCHN_SLOT, u8 buffer[], u8 len)
{
    u8 k, i = 0x00;
    if (len < 0x01)
        return (0);

    OS_ENTER_CRITICAL();
    while (len > 0x00)
    {
        if (0x00 == pCHN_SLOT->data_cnt)
        {
            pCHN_SLOT->tx = pCHN_SLOT->rx = INVALID_BLK_NO << BLK_NO_SHIFT;//00011111111  00000
            goto get_chn_exit;
        }
        if ((BLK_SZ - 1) == (pCHN_SLOT->tx & (BLK_SZ - 1)))
        {
            chn_pool_mgr.free_bitmap |= 1 << (pCHN_SLOT->tx >> BLK_NO_SHIFT);
            if (INVALID_BLK_NO == chn_pool_mgr.buffer[pCHN_SLOT->tx])
            {
                pCHN_SLOT->tx = pCHN_SLOT->rx = INVALID_BLK_NO << BLK_NO_SHIFT;
                pCHN_SLOT->data_cnt = 0x00;
                goto get_chn_exit;
            }
            pCHN_SLOT->tx = chn_pool_mgr.buffer[pCHN_SLOT->tx] << BLK_NO_SHIFT;
        }
        k = pCHN_SLOT->tx & (BLK_SZ - 1);
        k = (BLK_SZ - 1) - k;
        if (k > len)
            k = len;
        if (k > pCHN_SLOT->data_cnt)
            k = pCHN_SLOT->data_cnt;
        memcpy(&buffer[i], &chn_pool_mgr.buffer[pCHN_SLOT->tx], k);
        len -= k;
        pCHN_SLOT->tx += k;
        i += k;
        pCHN_SLOT->data_cnt -= k;
        if (pCHN_SLOT->data_cnt <= 0x00)
        {
            chn_pool_mgr.free_bitmap |= 1 << (pCHN_SLOT->tx >> BLK_NO_SHIFT);
            pCHN_SLOT->tx = pCHN_SLOT->rx = INVALID_BLK_NO << BLK_NO_SHIFT;
            goto get_chn_exit;
        }
    }
get_chn_exit:
    OS_EXIT_CRITICAL();


    return (i);
}

void empty_a_chn_slot(struct _CHN_SLOT *pCHN_SLOT, u16 len)
{
    unsigned char c;
    while (len > 0)
    {
        len--;
        get_chn_bytes(pCHN_SLOT, &c, 1);
    }
}
